/*
 * Copyright (C) 2007 Esmertec AG.
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.demonzym.framework.net.httpsocket.xml;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Map;

public class XmlPrimitiveSerializer implements PrimitiveSerializer {
    private String mVersionNs;
    private String mTransacNs;
    private StringBuffer strPrimitive;
    public XmlPrimitiveSerializer(String versionNs, String transacNs) {
        mVersionNs = versionNs;
        mTransacNs = transacNs;
    }
    public XmlPrimitiveSerializer() {        
    }

    public void serialize(Primitive primitive, OutputStream out) throws IOException {
        try {
            Writer writer = 
                new BufferedWriter(new OutputStreamWriter(out, "UTF-8"), 8192);

            //PrimitiveElement elem = primitive.createMessage(mVersionNs,
            //        mTransacNs);
            //writeElement(writer, elem);
            writeElement(writer, primitive.getContentElement());
            writer.flush();
            //String str=writeElementToString(elem);
            //writer.write(str);
        } catch (UnsupportedEncodingException e) {
            // Impossible. UTF-8 is always supported
            //ImpsLog.logError(e);
        }
    }
    public void serializeNMMPBytes(Primitive primitive, OutputStream out) throws IOException {
        try {
            /*Writer writer = 
                new BufferedWriter(new OutputStreamWriter(out, "UTF-8"), 8192);            
            String str=primitive.toString();                        
            int len=str.getBytes("UTF-8").length;            
            char [] charlength=new char[4];
            charlength[0] = (char)((len & 0xFF000000) >> 24);  //fill in the length (top number first)
            charlength[1] = (char)((len & 0x00FF0000) >> 16);  //fill in the lower part of the length
            charlength[2] = (char)((len & 0x0000FF00) >> 8);   //fill in the lower part of the length
            charlength[3] = (char)((len & 0x000000FF));	  //fill in the lower part of the length  
            writer.write(charlength);//should confirm whether it will write four bytes or not,if not,shoud take special step to make sure.
            writer.write(str);             
            writer.flush();*/
        	byte[] byContent = primitive.toString().getBytes("UTF-8");
        	int len=byContent.length;
        	byte [] byLength=new byte[4];
        	byLength[0] = (byte)((len & 0xFF000000) >> 24);  //fill in the length (top number first)
        	byLength[1] = (byte)((len & 0x00FF0000) >> 16);  //fill in the lower part of the length
        	byLength[2] = (byte)((len & 0x0000FF00) >> 8);   //fill in the lower part of the length
        	byLength[3] = (byte)((len & 0x000000FF));	  //fill in the lower part of the length
        	OutputStream stream = new BufferedOutputStream(out, 1024);
        	stream.write(byLength);
        	stream.write(byContent);
        	stream.flush();
        } catch (UnsupportedEncodingException e) {
            // Impossible. UTF-8 is always supported
            //ImpsLog.logError(e);
        }
    }
    public void serializeNMMP(Primitive primitive, OutputStream out) throws IOException {
        try {
            Writer writer = 
                new BufferedWriter(new OutputStreamWriter(out, "UTF-8"), 8192);
            //PrimitiveElement elem = primitive.createMessage(mVersionNs,
            //        mTransacNs);
            //String str=serializeToString(primitive.getContentElement());
            String str=primitive.toString();                   
            //int slen=str.length();
            int len=str.getBytes("UTF-8").length;            
            char [] charlength=new char[4];
            charlength[0] = (char)((len & 0xFF000000) >> 24);  //fill in the length (top number first)
            charlength[1] = (char)((len & 0x00FF0000) >> 16);  //fill in the lower part of the length
            charlength[2] = (char)((len & 0x0000FF00) >> 8);   //fill in the lower part of the length
            charlength[3] = (char)((len & 0x000000FF));	  //fill in the lower part of the length  
            writer.write(charlength);//should confirm whether it will write four bytes or not,if not,shoud take special step to make sure.
            writer.write(str);             
            writer.flush();
        } catch (UnsupportedEncodingException e) {
            // Impossible. UTF-8 is always supported
            //ImpsLog.logError(e);
        }
    }
    public void serializeNMMPString(String str, OutputStream out) throws IOException {
        try {
            Writer writer = 
                new BufferedWriter(new OutputStreamWriter(out, "UTF-8"), 8192);          
            //int len=str.length();
            int len=str.getBytes("UTF-8").length;
            char [] charlength=new char[4];
            charlength[0] = (char)((len & 0xFF000000) >> 24);  //fill in the length (top number first)
            charlength[1] = (char)((len & 0x00FF0000) >> 16);  //fill in the lower part of the length
            charlength[2] = (char)((len & 0x0000FF00) >> 8);   //fill in the lower part of the length
            charlength[3] = (char)((len & 0x000000FF));	  //fill in the lower part of the length  
            writer.write(charlength);//should confirm whether it will write four bytes or not,if not,shoud take special step to make sure.
            writer.write(str);
            writer.flush();
        } catch (UnsupportedEncodingException e) {
            // Impossible. UTF-8 is always supported
            //ImpsLog.logError(e);
        }
    }
    
    
    private void writeElement(Writer writer, PrimitiveElement element)
            throws IOException {
        writer.write('<');
        writer.write(element.getTagName());    
        Map<String, String> attrMap = element.getAttributes();
        if(attrMap != null && attrMap.size() > 0) {
            for (Map.Entry<String, String> entry : attrMap.entrySet()) {
                writer.write(' ');
                writer.write(entry.getKey());
                writer.write("=\"");
                writeEncoded(writer, entry.getValue());
                writer.write('"');
            }
        }

        if (element.getContents() != null) {
            writer.write('>');
            writeEncoded(writer, element.getContents());

            writer.write("</");
            writer.write(element.getTagName());
            writer.write('>');
        } else if (element.getChildCount() > 0) {
            writer.write('>');

            for (PrimitiveElement child : element.getChildren()) {
                writeElement(writer, child);
            }
            writer.write("</");
            writer.write(element.getTagName());
            writer.write('>');
        } else {
            writer.write("/>");
        }
    }
    public String  serializeToString(PrimitiveElement element)throws IOException {
    	strPrimitive= new StringBuffer();
    	return writeElementToString(element);
    }
	private String writeElementToString(PrimitiveElement element)
    throws IOException {
    	//StringBuffer strPrimitive = new StringBuffer("<"); 
		strPrimitive.append("<");		
    	strPrimitive.append(element.getTagName());    
		Map<String, String> attrMap = element.getAttributes();		
		if(attrMap != null && attrMap.size() > 0) {
		    for (Map.Entry<String, String> entry : attrMap.entrySet()) {
		    	strPrimitive.append(' ');
		    	strPrimitive.append(entry.getKey());
		    	strPrimitive.append("=\"");
		        writeEncoded(strPrimitive, entry.getValue());
		        strPrimitive.append('"');
		    }
		}
		
		if (element.getContents() != null) {
			strPrimitive.append('>');
		    writeEncoded(strPrimitive, element.getContents());
		
		    strPrimitive.append("</");
		    strPrimitive.append(element.getTagName());
		    strPrimitive.append('>');
		} else if (element.getChildCount() > 0) {
			strPrimitive.append('>');
		
		    for (PrimitiveElement child : element.getChildren()) {
		    	writeElementToString(child);
		    }
		    strPrimitive.append("</");
		    strPrimitive.append(element.getTagName());
		    strPrimitive.append('>');
		} else {
			strPrimitive.append("/>");
		}
		
		return strPrimitive.toString();
}
    private void writeEncoded(StringBuffer strBuf, String str) throws IOException {
        int len = str.length();
        for (int i = 0; i < len; i++) {
            char ch = str.charAt(i);

            switch (ch) {
                case '<':
                	strBuf.append("&lt;");
                    break;

                case '>':
                	strBuf.append("&gt;");
                    break;

                case '&':
                	strBuf.append("&amp;");
                    break;

                case '"':
                	strBuf.append("&quot;");
                    break;

                case '\'':
                	strBuf.append("&apos;");
                    break;

                default:
                	strBuf.append(ch);
            }
        }
    }

    private void writeEncoded(Writer writer, String str) throws IOException {
        int len = str.length();
        for (int i = 0; i < len; i++) {
            char ch = str.charAt(i);

            switch (ch) {
                case '<':
                    writer.write("&lt;");
                    break;

                case '>':
                    writer.write("&gt;");
                    break;

                case '&':
                    writer.write("&amp;");
                    break;

                case '"':
                    writer.write("&quot;");
                    break;

                case '\'':
                    writer.write("&apos;");
                    break;

                default:
                    writer.write(ch);
            }
        }
    }
}
